﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Telerik.Windows.Documents.Fixed.FormatProviders.Pdf;
using Telerik.Windows.Documents.Fixed.Model;
using Telerik.Windows.Documents.Fixed.Model.ColorSpaces;
using Telerik.Windows.Documents.Fixed.Model.Editing;
using Telerik.Windows.Documents.Fixed.Model.Editing.Tables;
using Telerik.Windows.Documents.Flow.FormatProviders.Html;
using Telerik.Windows.Documents.Flow.Model;
using Telerik.Windows.Documents.Fixed.Model.Resources;
using Telerik.Windows.Documents.Fixed.Model.Graphics;

namespace Console_4._7._2
{
    internal class Program
    {
        static void Main(string[] args)
        {
            RadFlowDocument htmlDocument;
            HtmlFormatProvider htmlFormatProvider = new HtmlFormatProvider();

            using (Stream input = File.OpenRead("..\\..\\..\\input.html"))
            {
                htmlDocument = htmlFormatProvider.Import(input, null);
            }

            Telerik.Windows.Documents.Flow.Model.Table htmlTable = htmlDocument.EnumerateChildrenOfType<Telerik.Windows.Documents.Flow.Model.Table>().FirstOrDefault();

            if (htmlTable == null)
            {
                System.Console.WriteLine("No table found in the HTML document.");
                return;
            }

            RadFixedDocument pdfDocument = new RadFixedDocument();
            
            // Convert HTML table to PDF tables across multiple pages
            ConvertHtmlTableToPdf(htmlTable, pdfDocument);

            // Save the PDF document
            PdfFormatProvider pdfProvider = new PdfFormatProvider();
            using (Stream output = File.Create("output.pdf"))
            {
                pdfProvider.Export(pdfDocument, output);
            }

            var psi = new ProcessStartInfo()
            {
                FileName = "output.pdf",
                UseShellExecute = true
            };
            Process.Start(psi);



        }

        static void ConvertHtmlTableToPdf(Telerik.Windows.Documents.Flow.Model.Table htmlTable, RadFixedDocument pdfDocument)
        {
            const double pageMargin = 72; // 1 inch margin
            const double maxTableWidth = 595.2 - (2 * pageMargin); // A4 width minus margins
            const double maxTableHeight = 841.8 - (2 * pageMargin); // A4 height minus margins

            RadFixedPage currentPage = pdfDocument.Pages.AddPage();
            FixedContentEditor currentEditor = new FixedContentEditor(currentPage);
            
            Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table currentPdfTable = new Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table();
            double currentTableHeight = 0;

            // Get all rows from the HTML table
            var htmlRows = htmlTable.Rows.ToList();
            int columnCount = htmlRows.Count > 0 ? htmlRows[0].Cells.Count : 0;
            
            for (int rowIndex = 0; rowIndex < htmlRows.Count; rowIndex++)
            {
                var htmlRow = htmlRows[rowIndex];
                
                // Calculate estimated row height BEFORE adding it to the table
                double estimatedRowHeight = CalculateEstimatedRowHeightFromHtmlRow(htmlRow, maxTableWidth / columnCount);
                double projectedTableHeight = currentTableHeight + estimatedRowHeight;
                
                // Check if adding this row would exceed page height
                if (projectedTableHeight > maxTableHeight && currentPdfTable.Rows.Count > 0)
                {
                    // Draw the current table on the page (without the current row)
                    DrawTableOnPage(currentEditor, currentPdfTable, pageMargin);
                    
                    // Create a new page and table
                    currentPage = pdfDocument.Pages.AddPage();
                    currentEditor = new FixedContentEditor(currentPage);
                    currentPdfTable = new Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table();
                    currentTableHeight = 0;
                }
                
                // Now add the current row to the table (either current or new)
                var pdfRow = currentPdfTable.Rows.AddTableRow();
                
                // Copy cells from HTML row to PDF row
                for (int cellIndex = 0; cellIndex < htmlRow.Cells.Count; cellIndex++)
                {
                    var htmlCell = htmlRow.Cells[cellIndex];
                    var pdfCell = pdfRow.Cells.AddTableCell();
                    
                    // Copy cell content including images
                    CopyCellContentToPdf(htmlCell, pdfCell, pdfDocument, maxTableWidth / columnCount);
                    
                    // Set cell properties with basic padding
                    var cellBorder = new Border(1, new RgbColor(0, 0, 0));
                    pdfCell.Borders = new TableCellBorders(cellBorder, cellBorder, cellBorder, cellBorder);
                    pdfCell.PreferredWidth = maxTableWidth / columnCount;
                }
                
                // Update the current table height
                currentTableHeight += estimatedRowHeight;
            }
            
            // Draw the final table if it has rows
            if (currentPdfTable.Rows.Count > 0)
            {
                DrawTableOnPage(currentEditor, currentPdfTable, pageMargin);
            }
        }

        static void CopyCellContentToPdf(Telerik.Windows.Documents.Flow.Model.TableCell htmlCell, 
            Telerik.Windows.Documents.Fixed.Model.Editing.Tables.TableCell pdfCell, 
            RadFixedDocument pdfDocument, double cellWidth)
        {
            foreach (var block in htmlCell.Blocks)
            {
                if (block is Paragraph paragraph)
                {
                    Block newParagraph = new Block();
                    
                    foreach (var inline in paragraph.Inlines)
                    {
                        if (inline is Run run)
                        {
                            newParagraph.InsertText(run.Text);
                        }
                        else if (inline is Telerik.Windows.Documents.Flow.Model.Shapes.ImageInline imageInline)
                        {
                            // Handle image inline
                            try
                            {
                                var imageSource = imageInline.Image.ImageSource;
                                if (imageSource != null)
                                {
                                    // Create image for PDF
                                    ImageSource pdfImageSource = new ImageSource(imageSource.Data, imageSource.Extension);
                                    pdfDocument.Resources.Images.Add(pdfImageSource);
                                    
                                    // Calculate image size to fit within cell
                                    double imageWidth = imageInline.Image.Width.Value;
                                    double imageHeight = imageInline.Image.Height.Value;
                                    
                                    // Scale image to fit within cell width if necessary
                                    if (imageWidth > cellWidth - 10) // Leave some padding
                                    {
                                        double scale = (cellWidth - 10) / imageWidth;
                                        imageWidth *= scale;
                                        imageHeight *= scale;
                                    }
                                    
                                    // Insert image into paragraph
                                    newParagraph.InsertImage(pdfImageSource, new Size(imageWidth, imageHeight));
                                }
                            }
                            catch (Exception ex)
                            {
                                // If image processing fails, insert placeholder text
                                newParagraph.InsertText("[Image]");
                                System.Console.WriteLine($"Failed to process image: {ex.Message}");
                            }
                        }
                    }
                    
                    pdfCell.Blocks.Add(newParagraph);
                }
                else if (block is Telerik.Windows.Documents.Flow.Model.Shapes.Table nestedTable)
                {
                    // Handle nested tables if needed
                    Block textBlock = new Block();
                    textBlock.InsertText("[Nested Table]");
                    pdfCell.Blocks.Add(textBlock);
                }
            }
        }

        static double CalculateEstimatedRowHeightFromHtmlRow(Telerik.Windows.Documents.Flow.Model.TableRow htmlRow, double cellWidth)
        {
            // Calculate estimated row height from HTML row before converting to PDF
            double baseRowHeight = 25; // Base height for a row
            double maxCellHeight = baseRowHeight;
            
            foreach (var htmlCell in htmlRow.Cells)
            {
                double cellHeight = baseRowHeight;
                
                // Add height for each block of content
                foreach (var block in htmlCell.Blocks)
                {
                    if (block is Paragraph paragraph)
                    {
                        // Count lines of text and images
                        int textLength = 0;
                        double maxImageHeight = 0;
                        
                        foreach (var inline in paragraph.Inlines)
                        {
                            if (inline is Run run)
                            {
                                textLength += run.Text.Length;
                            }
                            else if (inline is Telerik.Windows.Documents.Flow.Model.Shapes.ImageInline imageInline)
                            {
                                try
                                {
                                    double imageHeight = imageInline.Image.Height.Value;
                                    double imageWidth = imageInline.Image.Width.Value;
                                    
                                    // Scale image height if width needs to be scaled to fit cell
                                    if (imageWidth > cellWidth - 10)
                                    {
                                        double scale = (cellWidth - 10) / imageWidth;
                                        imageHeight *= scale;
                                    }
                                    
                                    maxImageHeight = Math.Max(maxImageHeight, imageHeight);
                                }
                                catch
                                {
                                    // Default image height if we can't read the actual dimensions
                                    maxImageHeight = Math.Max(maxImageHeight, 50);
                                }
                            }
                        }
                        
                        // Estimate lines based on character count (assuming ~50 chars per line)
                        int estimatedLines = Math.Max(1, textLength / 50);
                        double textHeight = (estimatedLines - 1) * 15;
                        
                        // Use the larger of text height or image height
                        cellHeight += Math.Max(textHeight, maxImageHeight);
                    }
                    else
                    {
                        cellHeight += 15; // Approximate height per non-paragraph block
                    }
                }
                
                if (cellHeight > maxCellHeight)
                {
                    maxCellHeight = cellHeight;
                }
            }
            
            return maxCellHeight;
        }

        static void DrawTableOnPage(FixedContentEditor editor, Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table table, double margin)
        {
            // Set table position
            editor.Position.Translate(margin, margin);
            
            // Draw the table
            editor.DrawTable(table);
        }
    }
}
